package org.grayrabbit.cloud.core.module;

import org.grayrabbit.cloud.core.beans.Creator;
import org.grayrabbit.cloud.core.beans.CreatorException;
import org.grayrabbit.cloud.core.biz.BizArgument;
import org.grayrabbit.cloud.core.biz.BizModule;
import org.grayrabbit.cloud.core.biz.BizResult;
import org.grayrabbit.cloud.core.biz.ServerUtility;
import org.grayrabbit.cloud.core.command.AbstractCommand;
import org.grayrabbit.cloud.core.command.CommandException;
import org.grayrabbit.cloud.core.config.ConfiguratorException;
import org.grayrabbit.cloud.core.handler.Handler;
import org.grayrabbit.cloud.core.handler.HandlerException;
import org.grayrabbit.cloud.core.rpc.Argument;
import org.grayrabbit.cloud.core.rpc.Result;
import org.grayrabbit.cloud.core.rpc.Server;
import org.grayrabbit.cloud.core.rpc.ServerException;
import org.grayrabbit.cloud.core.rpc.ServerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * @author sys53
 * @version 1.0
 * @created 11-6-2011 16:52:29
 */
public abstract class ServerModule<T extends Result, A extends Argument>
		implements Handler, Module<T, A> {
	private static final Logger logger = LoggerFactory
			.getLogger(ServerModule.class);
	protected String name;
	public Server server;

	public ServerModule() {
	}

	public ServerModule(String name, int port) throws ModuleConstructException {
		this.name = name;
		build(port);
	}

	private void build(int port) throws ModuleConstructException {
		if (port <= 0)
			throw new ModuleConstructException(
					String.format("Server(%s) port can't be < 0 ",
							new Object[] { this.name }));
		try {
			ServerFactory factory = getServerFactory();
			assert (factory != null);
			if (factory == null)
				throw new ModuleConstructException(String.format(
						"Server(%s) factory can't be null",
						new Object[] { this.name }));
			this.server = factory.create(port, this);
			this.server.run();
		} catch (ServerException e) {
			throw new ModuleConstructException(e);
		}
	}

	/**
	 * 
	 * @param param
	 * @throws ModuleConstructException
	 */
	public void construct(String name) throws ModuleConstructException {
		this.name = name;
		build(getServerPort());
	}

	public Result handle(Argument argument)
			throws HandlerException {
		try {
			BizArgument arg = (BizArgument) argument;
			logger.debug("Command is {}!",arg.getCommand());
			//判断是否存在代理模块
			try {
				BizModule module = ServerUtility.getModule("proxy");
				logger.debug("proxy module is {}.",module);
				if(module!=null){//存在代理服务器功能的时候，从远程访问
					if(ProxyModuleContext.getInstance().getKeys().contains(arg.getCommand())){
						logger.debug("{} Command exist.",arg.getCommand());
						//此处要构建远程连接的功能
						//TODO此处代码需重构
						return ProxyModuleContext.getInstance().getValue(arg.getCommand()).submit(arg);
					}
				}
			} catch (NoSuchModuleException e) {
				logger.warn("无代理模块");
			} catch (ModuleException e) {
				logger.error("代理模块执行出错",e);
				return BizResult.create(e);
			}
			
			String key = arg.getCommand();
			String className = ServerUtility.getProperty("command", key, "command");
			assert (className != null);
			logger.info("command class:{}",className);
			AbstractCommand command = (AbstractCommand) Creator.create(className);
			command.construct(arg);
			return (Result) command.execute();
		} catch (CommandException e) {
			return BizResult.create(e);
		} catch (CreatorException e) {
			return BizResult.create(e);
		} catch (ConfiguratorException e) {
			return BizResult.create(e);
		}
	}

	public void deconstruct() {
		try {
			if (this.server != null) {
				this.server.close();
			}
		} catch (ServerException e) {
			logger.error("服务器端关闭异常:", e);
		}
	}

	public String getName() {
		return this.name;
	}

	protected abstract ServerFactory getServerFactory();

	protected abstract int getServerPort();

	/**
	 * 
	 * @param param
	 */
	public T submit(A param) throws ModuleException {
		throw new ModuleException("ServerModule unsupport submit method");
	}

}